package mysql;

import com.mysql.jdbc.jdbc2.optional.MysqlXAConnection;
import com.mysql.jdbc.jdbc2.optional.MysqlXid;

import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.UUID;

/**
 * @Author: jc.huang
 * @Date: 2021/11/17
 */
public class XADemo {


    public static void main(String[] args) throws Exception {

        // 是否开启日志
        boolean logXaCommands = true;

        // 获取账户库的RM（ap做的事情）
        Connection accountConn = DriverManager.getConnection("jdbc:mysql://localhost:3306/xa_account?useUnicode=true&characterEncoding=utf8", "root", "root");
        XAConnection accConn = new MysqlXAConnection((com.mysql.jdbc.Connection) accountConn, logXaCommands);
        XAResource accountRm = accConn.getXAResource();

        // 获取红包库的RM
        Connection redConn = DriverManager.getConnection("jdbc:mysql://localhost:3306/xa_red_account?useUnicode=true&characterEncoding=utf8", "root", "root");
        XAConnection Conn2 = new MysqlXAConnection((com.mysql.jdbc.Connection) redConn, logXaCommands);
        XAResource redRm = Conn2.getXAResource();

        // XA 事务开始了

        // 全局事务
        byte[] globalId = UUID.randomUUID().toString().getBytes();
        // 就一个标识
        int formatId = 1;

        // 账户的分支事务
        byte[] accBqual = UUID.randomUUID().toString().getBytes();
        Xid xid = new MysqlXid(globalId, accBqual, formatId);

        // 红包分支事务
        byte[] redBqual = UUID.randomUUID().toString().getBytes();
        Xid xid1 = new MysqlXid(globalId, redBqual, formatId);

        try {

            // 账号事务开始 此时状态：ACTIVE
            accountRm.start(xid, XAResource.TMNOFLAGS);
            // 模拟业务
            String sql = "update account set balance_amount=balance_amount-90 where user_id=1";
            PreparedStatement ps = accountConn.prepareStatement(sql);
            ps.execute();
            accountRm.end(xid, XAResource.TMSUCCESS);
            // 账号 XA 事务 此时状态：IDLE

            // 红包分支事务开始 此时状态：ACTIVE
            redRm.start(xid1, XAResource.TMNOFLAGS);
            // 模拟业务
            String sql1 = "update account set balance_amount=balance_amount-10 where user_id=1";
            PreparedStatement ps1 = redConn.prepareStatement(sql1);
            ps1.execute();
            redRm.end(xid1, XAResource.TMSUCCESS);
            // 红包 XA 事务 此时状态：IDLE

            // 第一阶段：准备提交
            int rm1_prepare = accountRm.prepare(xid);
            int rm2_prepare = redRm.prepare(xid1);

            // XA 事务 此时状态：PREPARED

            //模拟异常
//            int i = 1 / 0;

            // 第二阶段：TM 根据第一阶段的情况决定是提交还是回滚
            //TM判断有2个事务分支，所以不能优化为一阶段提交
            boolean onePhase = false;
            if (rm1_prepare == XAResource.XA_OK && rm2_prepare == XAResource.XA_OK) {
                accountRm.commit(xid, onePhase);
                //模拟异常，accountRm提交事务后，就不能回滚了
//                int i = 1 / 0;
                redRm.commit(xid1, onePhase);
            } else {
                accountRm.rollback(xid);
                redRm.rollback(xid1);
            }
        } catch (Exception e) {
            // 出现异常，回滚
            accountRm.rollback(xid);
            redRm.rollback(xid1);
            e.printStackTrace();
        }
    }

}

